﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Clipping.Utils
{
    public class NewsParser
    {
        private static string[] labels = new string[] { "Script", "iframe", "STYLE", "DD", "NOSCRIPT", "title", "select" };

        private static string noiseregexpattern = @"[^\r\n]+版权与免责声明：?[\r\n]+";
        /// <summary>
        /// 提取当前页正文
        /// </summary>
        /// <param name="url"></param>
        /// <param name="pageNo"></param>
        /// <param name="content"></param>
        /// <param name="nextPage"></param>
        public static void GetContent(Uri url, int pageNo,IHtmlDownload htmlDownloader, out string content, out string channel, out Uri nextPage)
        {
            string html = "";
            string orihtml = "";
            try
            {
                html = htmlDownloader.GetHtml(url);
                orihtml = html;
            }
            catch
            {
                content = null;
                nextPage = null;
                channel = "";
            }
            removeUselessLabel(ref html);
            formatHtml(ref html);
            string html2 = findContentPart(html);
            content = formatcontent(html2, url);
            channel = findChannel(html);
            nextPage = getNextPage(orihtml, pageNo, url);

        }
        /// <summary>
        /// 提取当前页正文
        /// </summary>
        /// <param name="url"></param>
        /// <param name="html"></param>
        /// <param name="pageNo"></param>
        /// <param name="content"></param>
        /// <param name="nextPage"></param>
        public static void GetContent(Uri url, string html, int pageNo, out string content, out string channel, out Uri nextPage)
        {
            string orihtml = html;
            removeUselessLabel(ref html);
            formatHtml(ref html);
            string html2 = findContentPart(html);
            content = formatcontent(html2, url);
            channel = findChannel(html);
            nextPage = getNextPage(orihtml, pageNo, url);

        }
        /// <summary>
        /// 获取新闻频道
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private static string findChannel(string html)
        {
            Match m = Regex.Match(html, "(<a[^>]+?href\\s*=\\s*\"?[^\"\\s<>]+\"?[^>]*?>[^<>]+</a>(\\s*&gt;\\s*){1,3})+(<a[^>]+?href\\s*=\\s*\"?[^\"\\s<>]+\"?[^>]*?>[^<>]+</a>|[^\\r\\n]*?正文)", RegexOptions.IgnoreCase);
            if (m != null)
            {
                string rtn = Regex.Replace(m.Value, "\\s*<[^>]+>\\s*", "", RegexOptions.IgnoreCase);
                rtn = Regex.Replace(rtn, "\\s*&gt;\\s*", ">");
                rtn = Regex.Replace(rtn, ">+[^>]*正文$", "");
                return rtn;
            }
            else
                return "";
        }


        /// <summary>
        /// 获取连续新闻页正文
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public static string GetContentContinuously(Uri url,IHtmlDownload htmlDownloader, out string channel)
        {
            if (url == null)
            {
                channel = "";
                return "";
            }
            int pageNo = 1;
            string Content = "";
            string content;
            Uri nextpage;
            do
            {
                GetContent(url, pageNo, htmlDownloader, out content, out channel, out nextpage);
                Content += content;
                url = nextpage;
                pageNo++;
            }
            while (nextpage != null);
            return Content;
        }


        /// <summary>
        /// 去除部分HTML标记
        /// </summary>
        /// <param name="html"></param>
        private static void removeUselessLabel(ref string html)
        {
            if (string.IsNullOrEmpty(html))
                return;

            string regexstr;
            foreach (string s in labels)
            {
                regexstr = string.Format("<{0}[^>]*?>[\\s\\S]*?</{0}>", s);
                html = Regex.Replace(html, regexstr, "", RegexOptions.IgnoreCase);
            }
            html = Regex.Replace(html, "<!-+[\\s\\S]*?-+>", "", RegexOptions.IgnoreCase);
            html = Regex.Replace(html, "<(?!(a|div|td|table|tr|img|br|p|/a|/div|/td|/table|/tr|/p))[^>]*?>", "", RegexOptions.IgnoreCase);

        }

        /// <summary>
        /// 格式化HTML
        /// </summary>
        /// <param name="html"></param>
        private static void formatHtml(ref string html)
        {
            if (string.IsNullOrEmpty(html))
                return;
            html = Regex.Replace(html, "&nbsp;", " ", RegexOptions.IgnoreCase);
            html = Regex.Replace(html, "<div\\s+[^>]*>", "<div>", RegexOptions.IgnoreCase);
            html = Regex.Replace(html, "[\\r\\n]", "");
            html = Regex.Replace(html, ">\\s*", ">\r\n");
            html = Regex.Replace(html, "\\s*<", "\r\n<");
            html = Regex.Replace(html, "<\\r\\n", "&lt;");
            html = Regex.Replace(html, "\\r\\n>", "&gt;");
            html = Regex.Replace(html, "(?:<br[^>]*>|<p(>|[^>]*>)|</p>)\\s*", "\r\n", RegexOptions.IgnoreCase);
        }

        /// <summary>
        /// 找到HTML中的正文区域
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        private static string findContentPart(string html)
        {
            if (string.IsNullOrEmpty(html))
                return "";
            int maxlen = 0;
            string text = "";
            foreach (Match m in Regex.Matches(html, "<[^<>]*>([^<>]{10,})(?=<[^<>]*>)", RegexOptions.IgnoreCase))
            {
                if (m.Groups[1].Length > maxlen && !Regex.Match(m.Groups[1].Value, noiseregexpattern, RegexOptions.IgnoreCase).Success)
                {
                    maxlen = m.Groups[1].Length;
                    text = m.Groups[1].Value;
                }
            }
            if (string.IsNullOrEmpty(text))
                return "";

            int p = html.IndexOf(text);
            string tmpstr1 = html.Substring(0, p);
            string tmpstr2 = html.Substring(p);
            int f = 0;
            int tdend = 0;
            int divend = 0;
            int tdstart = 0;
            int divstart = 0;
            foreach (Match m in Regex.Matches(tmpstr2, "<(td[^>]*|/td)>", RegexOptions.IgnoreCase))
            {
                if (m.Groups[1].Value.StartsWith("/"))
                    f -= 1;
                else
                    f += 1;
                if (f == -1)
                {
                    tdend = m.Index;
                    break;
                }
            }
            f = 0;
            foreach (Match m in Regex.Matches(tmpstr2, "<(div|/div)>", RegexOptions.IgnoreCase))
            {
                if (m.Groups[1].Value.StartsWith("/"))
                    f -= 1;
                else
                    f += 1;
                if (f == -1)
                {
                    divend = m.Index;
                    break;
                }
            }
            f = 0;
            foreach (Match m in Regex.Matches(tmpstr1, "<(td[^>]*|/td)>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase))
            {
                if (m.Groups[1].Value.StartsWith("/"))
                    f -= 1;
                else
                    f += 1;
                if (f == 1)
                {
                    tdstart = m.Index + m.Length + 1;
                    break;
                }
            }
            f = 0;
            foreach (Match m in Regex.Matches(tmpstr1, "<(div|/div)>", RegexOptions.RightToLeft | RegexOptions.IgnoreCase))
            {
                if (m.Groups[1].Value.StartsWith("/"))
                    f -= 1;
                else
                    f += 1;
                if (f == 1)
                {
                    divstart = m.Index + m.Length + 1;
                    break;
                }
            }
            if ((tdend < divend || divend == 0) && tdstart != 0 && tdend != 0)
            {
                return html.Substring(tdstart, p + tdend - tdstart - 1);
            }
            else if ((tdend > divend || tdend == 0) && divstart != 0 && divend != 0)
            {
                return html.Substring(divstart, p + divend - divstart - 1);
            }
            else
            {
                return "";
            }
        }

        /// <summary>
        /// 格式化正文
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        private static string formatcontent(string content, Uri url)
        {
            if (string.IsNullOrEmpty(content))
                return "";
            foreach (Match m in Regex.Matches(content, "(?:\\r\\n)?<img\\s[^>]*?src\\s*=\\s*(?:'|\")?(?<img>[^'\">]*)(?:'|\")?[^>]*>(?:\\r\\n){0,1}", RegexOptions.IgnoreCase))
            {
                if (Regex.Match(m.Groups["img"].Value, "icon|logo", RegexOptions.IgnoreCase).Success)
                {
                    content = content.Replace(m.Value, "");
                }
                try
                {
                    Uri imguri = new Uri(url, m.Groups["img"].Value);
                    string img = m.Value.Replace(m.Groups["img"].Value, imguri.OriginalString);
                    content = content.Replace(m.Value, img);
                }
                catch
                { }
            }
            content = Regex.Replace(content, "(?:\\r\\n)?<(a\\s+[^>]*|/a)>(?:\\r\\n)?", "", RegexOptions.IgnoreCase);
            content = Regex.Replace(content, "<(?:table|tr|/table|/tr)[^>]*>", "", RegexOptions.IgnoreCase);
            while (Regex.Match(content, "<td[^>]*>[^<>]*</td>", RegexOptions.IgnoreCase).Success)
            {
                content = Regex.Replace(content, "<td[^>]*>[^<>]*</td>", "", RegexOptions.IgnoreCase);
            }
            content = Regex.Replace(content, "<(?:td|/td)[^>]*>", "", RegexOptions.IgnoreCase);
            content = Regex.Replace(content, ">\\s*", ">\r\n");
            content = Regex.Replace(content, "\\s*<", "\r\n<");
            content = Regex.Replace(content, "[\\r\\n]+", "</p>\r\n<p>　　");
            content = Regex.Replace(content, "^\\s*", "<p>　　");
            content = Regex.Replace(content, "\\s*$", "</p>");
            content = Regex.Replace(content, "<p>(?=　　<img\\s[^>]*></p>)", "<p align=center>", RegexOptions.IgnoreCase);
            content = Regex.Replace(content, "(^<p>　　</p>|<p></p></p>$)", "", RegexOptions.IgnoreCase);
            return content;



        }

        /// <summary>
        /// 取得下一页地址
        /// </summary>
        /// <param name="html2"></param>
        /// <param name="currentPageNo"></param>
        /// <param name="currentUrl"></param>
        /// <returns></returns>
        private static Uri getNextPage(string html2, int currentPageNo, Uri currentUrl)
        {
            string screentip;
            int nextPageNo = currentPageNo + 1;
            Uri uri;
            if (string.IsNullOrEmpty(html2))
                return null;
            foreach (Match m in Regex.Matches(html2, "<A[^>]*?HREF\\s*=\\s*(?:\"|')?([^\"'<>\\s]*)(?:\"|')?[^>]*?>\\s*([\\s\\S]*?)\\s*<\\/A>", RegexOptions.IgnoreCase))
            {
                uri = null;
                try
                {
                    uri = new Uri(m.Groups[1].Value, UriKind.RelativeOrAbsolute);
                }
                catch { continue; }

                screentip = m.Groups[2].Value;
                screentip = Regex.Replace(screentip, "【|】|\\[|\\]|\\(|\\)|（|）|<|>|\\s", "");
                if (Regex.IsMatch(screentip, string.Format("^第?{0}页?$", nextPageNo)) || Regex.IsMatch(screentip, "^(下一页|后一页|下页|后页)$"))
                {
                    Uri nextpageuri = null;
                    if (uri.IsAbsoluteUri)
                    {
                        if (getUrlPath(currentUrl) == getUrlPath(uri))
                            nextpageuri = uri;
                        else
                            nextpageuri = null;
                    }
                    else
                    {
                        if (uri.OriginalString.IndexOf("?") == 0)
                        {
                            nextpageuri = new Uri(currentUrl.OriginalString.Replace(currentUrl.Query, "") + uri.OriginalString);
                        }
                        else
                        {
                            nextpageuri = new Uri(currentUrl, uri);
                            if (getUrlPath(currentUrl) != getUrlPath(nextpageuri))
                                nextpageuri = null;
                        }
                    }
                    if (nextpageuri != null)
                        return nextpageuri;
                }
            }
            return null;
        }


        private static string getUrlPath(Uri uri)
        {
            if (uri == null)
                return null;
            string url = uri.OriginalString;
            int index = url.LastIndexOf("/");
            if (index > 0)
                return url.Substring(0, index);
            else
                return url;

        }
        //private static string replacetm(Match m)
        //{
        //    if (m.Groups[1].Value.StartsWith("#"))
        //    { 
        //    charcode=int.Parse (m.Groups [1].Value .Substring (
        //    }

        //}

        //private static string replactimg(Match m)
        //{
        //    if (Regex.Match(m.Groups["img"].Value, "icon|logo", RegexOptions.IgnoreCase).Success)
        //        return "";
        //    else 
        //    {




        //    }

        //}

        /// <summary>
        /// 统计字数
        /// </summary>
        /// <param name="html"></param>
        /// <returns></returns>
        public static int CountWords(string html)
        {
            int chwords = 0;
            int enwords = 0;
            if (string.IsNullOrEmpty(html))
                return 0;
            html = html.Trim();
            html = Regex.Replace(html, "<[^>]*>", "");
            chwords = Regex.Matches(html, @"[^\u0000-\u007f,\s]").Count;
            foreach (Match m in Regex.Matches(html, @"[\u0000-\u007f]*"))
            {
                string tmpstr = m.Value.Trim();
                if (!string.IsNullOrEmpty(tmpstr))
                {
                    tmpstr = string.Format("\t{0}\t", tmpstr);
                    enwords += Regex.Matches(tmpstr, "\\s+").Count - 1;
                }
            }
            return chwords + enwords;
        }
    }
}
